﻿﻿using api_identity.Data.Entities;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace api_identity.Data
{
    public class ApplicationDbContext : IdentityDbContext<UserEntity, RoleEntity, string>
    {
        private readonly IActionDescriptorCollectionProvider _actionDescriptor;

        public ApplicationDbContext(DbContextOptions options, IActionDescriptorCollectionProvider actionDescriptor)
            : base(options)
        {
            this._actionDescriptor = actionDescriptor;

            base.Database.EnsureCreated();
            this.InitPermissionsData();// 每次启动程序，自动更新权限表
        }

        #region Tables

        public DbSet<PermissionsEntity> Permissions { get; set; }

        public DbSet<RolePermissionsEntity> RolePermissions { get; set; }

        public DbSet<RefreshTokenEntity> RefreshTokens { get; set; }

        #endregion

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Entity<RoleEntity>(b =>
            {
                b.HasMany<RolePermissionsEntity>().WithOne().HasForeignKey(rp => rp.RoleId).IsRequired();
            });

            builder.Entity<PermissionsEntity>(b =>
            {
                b.HasKey(p => p.Id);
                b.ToTable("AspNetPermissions");
                b.Property(p => p.ConcurrencyStamp).IsConcurrencyToken();
                b.Property(p => p.Name).HasMaxLength(256);
                b.Property(p => p.ControllerName).HasMaxLength(256);
                b.Property(p => p.ActionName).HasMaxLength(256);

                b.HasMany<RolePermissionsEntity>().WithOne().HasForeignKey(rp => rp.PermissionsId).IsRequired();
            });

            builder.Entity<RolePermissionsEntity>(b =>
            {
                b.HasKey(r => new { r.PermissionsId, r.RoleId });
                b.ToTable("AspNetRolePermissions");
            });

            builder.Entity<UserEntity>(b =>
            {
                b.HasMany<RefreshTokenEntity>().WithOne().HasForeignKey(rt => rt.UserId).IsRequired();
            });

            builder.Entity<RefreshTokenEntity>(b =>
            {
                b.HasKey(rt => rt.Id);
                b.ToTable("AspNetRefreshTokens");
                b.Property(rt => rt.Key).HasMaxLength(256).IsRequired();
                b.Property(rt => rt.ExpireTimeStamp).IsRequired();
            });
        }

        private void InitPermissionsData()
        {
            var permissions = this.GetPermissions();

            //清空，重新添加
            this.Permissions.RemoveRange(this.Permissions);
            this.Permissions.AddRange(permissions);
            base.SaveChanges();
        }
        IList<PermissionsEntity> GetPermissions()
        {
            var list = new List<PermissionsEntity>();
            foreach (var actionDescriptor in this._actionDescriptor.ActionDescriptors.Items)
            {
                actionDescriptor.RouteValues.TryGetValue("controller", out string cName);
                actionDescriptor.RouteValues.TryGetValue("action", out string aName);
                if (string.IsNullOrEmpty(cName) || string.IsNullOrEmpty(aName))
                {
                    continue;
                }

                var requestMethod = actionDescriptor.EndpointMetadata.FirstOrDefault(m => m is Microsoft.AspNetCore.Routing.HttpMethodMetadata);
                //requestMethod.HttpMethods //获取请求方式
                //requestMethod.AcceptCorsPreflight //获取是否跨域

                bool authorizationFlag = actionDescriptor.EndpointMetadata.Any(m => m is Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute)
                    || !actionDescriptor.EndpointMetadata.Any(m => m is Microsoft.AspNetCore.Authorization.AuthorizeAttribute);

                if (authorizationFlag || requestMethod == null)
                {//跳过 忽略授权 没有授权特性 未指定请求方式
                    continue;
                }
                string name = actionDescriptor.DisplayName;// TODO: 添加特性获取显示名称
                list.Add(new PermissionsEntity(controllerName: cName, actionName: aName)
                {
                    Id = this.ToMd5(name),
                    Name = name
                });
            }
            return list;
        }

        string ToMd5(string source, Encoding encoding = null)
        {
            byte[] bytes = (encoding ?? Encoding.UTF8).GetBytes(source);
            using MD5 md5 = new MD5CryptoServiceProvider();
            byte[] desBytes = md5.ComputeHash(bytes);
            return BitConverter.ToString(desBytes).Replace("-", "");
        }

    }
}
